From 83120737f5c6015013ed98deddff36d10ca058ac Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Fri, 25 Nov 2005 18:43:35 +0100 Subject: [PATCH] Implement new memory_op() XENMEM_machphys_mfn_list. Replaces old privcmd Linux ioctl and includes an implementation for x86/64. Signed-off-by: Keir Fraser --- .../drivers/xen/privcmd/privcmd.c | 49 ------------------- .../include/asm-xen/linux-public/privcmd.h | 7 --- tools/libxc/xc_linux_save.c | 31 +++++------- tools/libxc/xc_private.c | 20 ++++++++ xen/arch/x86/x86_32/mm.c | 36 ++++++++++++++ xen/arch/x86/x86_64/mm.c | 46 +++++++++++++++++ xen/common/memory.c | 2 +- xen/include/asm-ia64/mm.h | 3 ++ xen/include/asm-x86/mm.h | 5 +- xen/include/public/memory.h | 28 +++++++++++ 10 files changed, 151 insertions(+), 76 deletions(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c b/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c index 0b0084b31e..dff9343c5f 100644 --- a/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c +++ b/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c @@ -213,55 +213,6 @@ static int privcmd_ioctl(struct inode *inode, struct file *file, break; #endif -#ifndef __ia64__ - case IOCTL_PRIVCMD_GET_MACH2PHYS_MFNS: { - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd; - unsigned long m2pv, m2p_mfn; - privcmd_m2pmfns_t m; - unsigned long __user *p; - int i; - -#if defined (__x86_64__) - /* - ** XXX SMH: the below procedure won't work for 64 since - ** we don't have access to the memory which maps the M2P. - ** A proper fix will probably involve moving this - ** functionality to Xen - for now just return an error - ** here rather than GPF'ing in the kernel. - */ - ret = -EINVAL; - break; -#endif - - if (copy_from_user(&m, udata, sizeof(m))) - return -EFAULT; - - m2pv = (unsigned long)machine_to_phys_mapping; - - p = m.arr; - - for (i=0; i < m.num; i++) { - pgd = pgd_offset_k(m2pv); - pud = pud_offset(pgd, m2pv); - pmd = pmd_offset(pud, m2pv); - m2p_mfn = (*(uint64_t *)pmd >> PAGE_SHIFT)&0xFFFFFFFF; - m2p_mfn += pte_index(m2pv); - - if (put_user(m2p_mfn, p + i)) - return -EFAULT; - - m2pv += (1 << 21); - } - - ret = 0; - break; - - } - break; -#endif - default: ret = -EINVAL; break; diff --git a/linux-2.6-xen-sparse/include/asm-xen/linux-public/privcmd.h b/linux-2.6-xen-sparse/include/asm-xen/linux-public/privcmd.h index 3c91205855..074d66c79b 100644 --- a/linux-2.6-xen-sparse/include/asm-xen/linux-public/privcmd.h +++ b/linux-2.6-xen-sparse/include/asm-xen/linux-public/privcmd.h @@ -59,11 +59,6 @@ typedef struct privcmd_mmapbatch { unsigned long __user *arr; /* array of mfns - top nibble set on err */ } privcmd_mmapbatch_t; -typedef struct privcmd_m2pmfns { - int num; /* max number of mfns to return */ - unsigned long __user *arr; /* array of mfns */ -} privcmd_m2pmfns_t; - typedef struct privcmd_blkmsg { unsigned long op; @@ -82,8 +77,6 @@ typedef struct privcmd_blkmsg _IOC(_IOC_NONE, 'P', 2, sizeof(privcmd_mmap_t)) #define IOCTL_PRIVCMD_MMAPBATCH \ _IOC(_IOC_NONE, 'P', 3, sizeof(privcmd_mmapbatch_t)) -#define IOCTL_PRIVCMD_GET_MACH2PHYS_MFNS \ - _IOC(_IOC_READ, 'P', 4, sizeof(unsigned long)) #endif /* __LINUX_PUBLIC_PRIVCMD_H__ */ diff --git a/tools/libxc/xc_linux_save.c b/tools/libxc/xc_linux_save.c index af2aec1fb1..467598fec4 100644 --- a/tools/libxc/xc_linux_save.c +++ b/tools/libxc/xc_linux_save.c @@ -502,7 +502,7 @@ static unsigned long *xc_map_m2p(int xc_handle, unsigned long max_mfn, int prot) { - privcmd_m2pmfns_t m2p_mfns; + struct xen_machphys_mfn_list xmml; privcmd_mmap_t ioctlx; privcmd_mmap_entry_t *entries; unsigned long m2p_chunks, m2p_size; @@ -512,50 +512,45 @@ static unsigned long *xc_map_m2p(int xc_handle, m2p_size = M2P_SIZE(max_mfn); m2p_chunks = M2P_CHUNKS(max_mfn); - - m2p_mfns.num = m2p_chunks; - - if(!(m2p_mfns.arr = malloc(m2p_chunks * sizeof(unsigned long)))) { + xmml.max_extents = m2p_chunks; + if (!(xmml.extent_start = malloc(m2p_chunks * sizeof(unsigned long)))) { ERR("failed to allocate space for m2p mfns!\n"); return NULL; } - if (ioctl(xc_handle, IOCTL_PRIVCMD_GET_MACH2PHYS_MFNS, &m2p_mfns) < 0) { + if (xc_memory_op(xc_handle, XENMEM_machphys_mfn_list, &xmml) || + (xmml.nr_extents != m2p_chunks)) { ERR("xc_get_m2p_mfns:"); return NULL; } - if((m2p = mmap(NULL, m2p_size, prot, - MAP_SHARED, xc_handle, 0)) == MAP_FAILED) { + if ((m2p = mmap(NULL, m2p_size, prot, + MAP_SHARED, xc_handle, 0)) == MAP_FAILED) { ERR("failed to mmap m2p"); return NULL; } - - if(!(entries = malloc(m2p_chunks * sizeof(privcmd_mmap_entry_t)))) { + if (!(entries = malloc(m2p_chunks * sizeof(privcmd_mmap_entry_t)))) { ERR("failed to allocate space for mmap entries!\n"); return NULL; } - ioctlx.num = m2p_chunks; ioctlx.dom = DOMID_XEN; ioctlx.entry = entries; - for(i=0; i < m2p_chunks; i++) { - + for (i=0; i < m2p_chunks; i++) { entries[i].va = (unsigned long)(((void *)m2p) + (i * M2P_CHUNK_SIZE)); - entries[i].mfn = m2p_mfns.arr[i]; + entries[i].mfn = xmml.extent_start[i]; entries[i].npages = M2P_CHUNK_SIZE >> PAGE_SHIFT; - } - if((rc = ioctl(xc_handle, IOCTL_PRIVCMD_MMAP, &ioctlx)) < 0) { + if ((rc = ioctl(xc_handle, IOCTL_PRIVCMD_MMAP, &ioctlx)) < 0) { ERR("ioctl_mmap failed (rc = %d)", rc); return NULL; } - - free(m2p_mfns.arr); + + free(xmml.extent_start); free(entries); return m2p; diff --git a/tools/libxc/xc_private.c b/tools/libxc/xc_private.c index 2c7759336e..75556f6847 100644 --- a/tools/libxc/xc_private.c +++ b/tools/libxc/xc_private.c @@ -190,6 +190,7 @@ int xc_memory_op(int xc_handle, { DECLARE_HYPERCALL; struct xen_memory_reservation *reservation = arg; + struct xen_machphys_mfn_list *xmml = arg; long ret = -EINVAL; hypercall.op = __HYPERVISOR_memory_op; @@ -214,6 +215,20 @@ int xc_memory_op(int xc_handle, goto out1; } break; + case XENMEM_machphys_mfn_list: + if ( mlock(xmml, sizeof(*xmml)) != 0 ) + { + PERROR("Could not mlock"); + goto out1; + } + if ( mlock(xmml->extent_start, + xmml->max_extents * sizeof(unsigned long)) != 0 ) + { + PERROR("Could not mlock"); + safe_munlock(xmml, sizeof(*xmml)); + goto out1; + } + break; } ret = do_xen_hypercall(xc_handle, &hypercall); @@ -227,6 +242,11 @@ int xc_memory_op(int xc_handle, safe_munlock(reservation->extent_start, reservation->nr_extents * sizeof(unsigned long)); break; + case XENMEM_machphys_mfn_list: + safe_munlock(xmml, sizeof(*xmml)); + safe_munlock(xmml->extent_start, + xmml->max_extents * sizeof(unsigned long)); + break; } out1: diff --git a/xen/arch/x86/x86_32/mm.c b/xen/arch/x86/x86_32/mm.c index 798865d370..d1c625956a 100644 --- a/xen/arch/x86/x86_32/mm.c +++ b/xen/arch/x86/x86_32/mm.c @@ -27,6 +27,7 @@ #include #include #include +#include extern l1_pgentry_t *mapcache; @@ -184,6 +185,41 @@ void subarch_init_memory(struct domain *dom_xen) } } +long arch_memory_op(int op, void *arg) +{ + struct xen_machphys_mfn_list xmml; + unsigned long mfn; + unsigned int i, max; + long rc = 0; + + switch ( op ) + { + case XENMEM_machphys_mfn_list: + if ( copy_from_user(&xmml, arg, sizeof(xmml)) ) + return -EFAULT; + + max = min_t(unsigned int, xmml.max_extents, mpt_size >> 21); + + for ( i = 0; i < max; i++ ) + { + mfn = l2e_get_pfn(idle_pg_table_l2[l2_linear_offset( + RDWR_MPT_VIRT_START + (i << 21))]) + l1_table_offset(i << 21); + if ( put_user(mfn, &xmml.extent_start[i]) ) + return -EFAULT; + } + + if ( put_user(i, &((struct xen_machphys_mfn_list *)arg)->nr_extents) ) + return -EFAULT; + + break; + + default: + rc = -ENOSYS; + break; + } + + return rc; +} long do_stack_switch(unsigned long ss, unsigned long esp) { diff --git a/xen/arch/x86/x86_64/mm.c b/xen/arch/x86/x86_64/mm.c index a20c900fb0..a9e71746c6 100644 --- a/xen/arch/x86/x86_64/mm.c +++ b/xen/arch/x86/x86_64/mm.c @@ -28,6 +28,7 @@ #include #include #include +#include struct pfn_info *alloc_xen_pagetable(void) { @@ -174,6 +175,51 @@ void subarch_init_memory(struct domain *dom_xen) } } +long arch_memory_op(int op, void *arg) +{ + struct xen_machphys_mfn_list xmml; + l3_pgentry_t l3e; + l2_pgentry_t l2e; + unsigned long mfn, v; + unsigned int i; + long rc = 0; + + switch ( op ) + { + case XENMEM_machphys_mfn_list: + if ( copy_from_user(&xmml, arg, sizeof(xmml)) ) + return -EFAULT; + + for ( v = RDWR_MPT_VIRT_START; v != RDWR_MPT_VIRT_END; v += 1 << 21 ) + { + l3e = l4e_to_l3e(idle_pg_table[l4_table_offset(v)])[ + l3_table_offset(v)]; + if ( !(l3e_get_flags(l3e) & _PAGE_PRESENT) ) + break; + l2e = l3e_to_l2e(l3e)[l2_table_offset(v)]; + if ( !(l2e_get_flags(l2e) & _PAGE_PRESENT) ) + break; + mfn = l2e_get_pfn(l2e) + l1_table_offset(v); + if ( i == xmml.max_extents ) + break; + if ( put_user(mfn, &xmml.extent_start[i]) ) + return -EFAULT; + i++; + } + + if ( put_user(i, &((struct xen_machphys_mfn_list *)arg)->nr_extents) ) + return -EFAULT; + + break; + + default: + rc = -ENOSYS; + break; + } + + return rc; +} + long do_stack_switch(unsigned long ss, unsigned long esp) { if ( (ss & 3) != 3 ) diff --git a/xen/common/memory.c b/xen/common/memory.c index 79d6dca2e3..49a0802a50 100644 --- a/xen/common/memory.c +++ b/xen/common/memory.c @@ -215,7 +215,7 @@ long do_memory_op(int cmd, void *arg) break; default: - rc = -ENOSYS; + rc = arch_memory_op(op, arg); break; } diff --git a/xen/include/asm-ia64/mm.h b/xen/include/asm-ia64/mm.h index 8ab80ab5dc..e38ba4f149 100644 --- a/xen/include/asm-ia64/mm.h +++ b/xen/include/asm-ia64/mm.h @@ -440,4 +440,7 @@ extern unsigned long lookup_domain_mpa(struct domain *d, unsigned long mpaddr); #define __gpa_to_mpa(_d, gpa) \ ((__gpfn_to_mfn((_d),(gpa)>>PAGE_SHIFT)<